home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 109 / EnigmaAmiga109CD.iso / dalla rivista / amiga.free / sorgenti vari / wolf3dmacsource.sit / Wolf3DMacSource / RefBsp.c < prev    next >
C/C++ Source or Header  |  1994-09-29  |  13KB  |  487 lines

  1. #include "WolfDef.h"
  2.  
  3. static Word checkcoord[11][4] = {    /* Indexs to the bspcoord table */
  4. {3,0,2,1},
  5. {3,0,2,0},
  6. {3,1,2,0},
  7. {0,0,0,0},
  8. {2,0,2,1},
  9. {0,0,0,0},        /* Not valid */
  10. {3,1,3,0},
  11. {0,0,0,0},
  12. {2,0,3,1},
  13. {2,1,3,1},
  14. {2,1,3,0}};
  15.  
  16. /**********************************
  17.  
  18.     Draw a 3-D textured polygon, must be done FAST!
  19.         
  20. **********************************/
  21.  
  22. void RenderWallLoop(Word x1,Word x2,Word distance)
  23. {
  24.     fixed_t    texturecolumn;
  25.     Word tile,scaler, angle;
  26.     
  27. /* calculate and draw each column */
  28.     
  29.     if (rw_downside) {
  30.         while (x1 < x2) {        /* Time to draw? */
  31.             scaler = rw_scale >> FRACBITS;        /* Get the draw scale */
  32.             xscale[x1] = scaler;        /* Save the scale factor */
  33.             angle = xtoviewangle[x1]+rw_centerangle;
  34.             texturecolumn = rw_midpoint - SUFixedMul(finetangent[angle],distance);    /* Which texture to use? */    
  35.             if ((Word)texturecolumn < rw_mintex) {
  36.                 texturecolumn = rw_mintex;
  37.             } else if ((Word)texturecolumn >= rw_maxtex) {
  38.                 texturecolumn = rw_maxtex-1;
  39.             }
  40.             tile = rw_texture[texturecolumn>>8];    /* Get the tile to use */
  41.             IO_ScaleWallColumn(x1,scaler,tile,(texturecolumn>>1)&127);    /* Draw the line */
  42.             ++x1;                        /* Next x */
  43.             rw_scale+=rw_scalestep;        /* Step the scale factor for the wall */
  44.         }
  45.         return;
  46.     }
  47.     while (x1 < x2) {        /* Time to draw? */
  48.         scaler = rw_scale >> FRACBITS;        /* Get the draw scale */
  49.         xscale[x1] = scaler;        /* Save the scale factor */
  50.         angle = xtoviewangle[x1]+rw_centerangle;
  51.         texturecolumn = SUFixedMul(finetangent[angle],distance)+rw_midpoint;    /* Which texture to use? */
  52.         if ((Word)texturecolumn < rw_mintex) {
  53.             texturecolumn = rw_mintex;
  54.         } else if ((Word)texturecolumn >= rw_maxtex) {
  55.             texturecolumn = rw_maxtex-1;
  56.         }
  57.         tile = rw_texture[texturecolumn>>8];    /* Get the tile to use */
  58.         if (!(WallListPtr[tile+1] & 0x4000)) {
  59.             texturecolumn^=0xff;    /* Reverse the tile for N,W walls */
  60.         }
  61.         IO_ScaleWallColumn(x1,scaler,tile,(texturecolumn>>1)&127);    /* Draw the line */
  62.         ++x1;                        /* Next x */
  63.         rw_scale+=rw_scalestep;        /* Step the scale factor for the wall */
  64.     }
  65. }
  66.  
  67.  
  68. /*
  69. =====================
  70. =
  71. = RenderWallRange
  72. =
  73. = Draw a wall segment between start and stop angles (inclusive) (short angles)
  74. = No clipping is needed
  75. =
  76. ======================
  77. */
  78.  
  79. void RenderWallRange (Word start,Word stop,saveseg_t *seg,Word distance)
  80. {
  81.     LongWord scale2;
  82.     Word vangle;
  83.     Word x1,x2;
  84.  
  85. /* mark the segment as visible for auto map*/
  86.  
  87.     seg->dir |= DIR_SEENFLAG;        /* for automap*/
  88.     areavis[seg->area] = 1;            /* for sprite drawing*/
  89.     
  90.     start -= ANGLE180;        /* Adjust the start angle */
  91.     stop -= ANGLE180;        /* Adjust the stop angle */
  92.     vangle = (Word)(start+ANGLE90)>>ANGLETOFINESHIFT;
  93.     x1 = viewangletox[vangle];
  94.     vangle = (Word)(stop+ANGLE90-1)>>ANGLETOFINESHIFT;    /* make non inclusive*/
  95.     x2 = viewangletox[vangle];
  96.     if (x2 == x1) {
  97.         return;        /* less than one column wide*/
  98.     }
  99.     rw_scale = (long) ScaleFromGlobalAngle(start+centershort,distance)<<FRACBITS;
  100.     if (x2>x1+1) {
  101.         scale2 = (long) ScaleFromGlobalAngle(stop+centershort,distance)<<FRACBITS;
  102.         rw_scalestep = (long)(scale2-rw_scale)/(long)(x2-x1);
  103.     }
  104.     RenderWallLoop(x1,x2,distance);
  105. }
  106.  
  107. /*
  108. ===============================================================================
  109. =
  110. = ClipWallSegment
  111. =
  112. = Clips the given screenpost and includes it in newcolumn
  113. ===============================================================================
  114. */
  115.  
  116. /* a screenpost_t is a solid range of visangles, used to clip and detect*/
  117. /* span exposures / hidings*/
  118.  
  119. typedef    struct {
  120.     Word top, bottom;
  121. } screenpost_t;
  122.  
  123. #define    MAXSEGS    16
  124.  
  125. screenpost_t solidsegs[MAXSEGS], *newend;    /* newend is one past the last valid seg */
  126.  
  127. void ClipWallSegment(Word top,Word bottom,saveseg_t *seg,Word distance)
  128. {
  129.     screenpost_t *next, *start;
  130.     
  131. /* find the first clippost that touches the source post (adjacent pixels are touching)*/
  132.     start = solidsegs;
  133.     while (start->bottom > top+1) {
  134.         start++;
  135.     }
  136.  
  137.     if (top > start->top) {
  138.         if (bottom > start->top+1) {    /* post is entirely visible (above start), so insert a new clippost*/
  139.             RenderWallRange(top, bottom,seg,distance);
  140.             next = newend;
  141.             newend++;
  142.             while (next != start) {
  143.                 *next = *(next-1);
  144.                 next--;
  145.             }
  146.             next->top = top;
  147.             next->bottom = bottom;
  148.             return;
  149.         }
  150.         
  151.     /* there is a fragment above *start*/
  152.         RenderWallRange (top, start->top + 1,seg,distance);
  153.         start->top = top;        /* adjust the clip size*/
  154.     }
  155.     
  156.     if (bottom >= start->bottom)
  157.         return;            /* bottom contained in start*/
  158.         
  159.     next = start;
  160.     while (bottom <= (next+1)->top+1) {
  161.         /* there is a fragment between two posts*/
  162.         RenderWallRange (next->bottom - 1, (next+1)->top + 1,seg,distance);
  163.         next++;
  164.         if (bottom >= next->bottom) {    /* bottom is contained in next*/
  165.             start->bottom = next->bottom;    /* adjust the clip size*/
  166.             goto crunch;
  167.         }
  168.     }
  169.     
  170.     /* there is a fragment after *next*/
  171.     RenderWallRange (next->bottom - 1, bottom,seg,distance);
  172.     start->bottom = bottom;        /* adjust the clip size*/
  173.     
  174.     
  175. /* remove start+1 to next from the clip list, because start now covers their area*/
  176. crunch:
  177.     if (next == start) {
  178.         return;            /* post just extended past the bottom of one post*/
  179.     }
  180.     while (next++ != newend)    /* remove a post*/
  181.         *++start = *next;
  182.     newend = start+1;
  183. }
  184.  
  185. /**********************************
  186.  
  187.     Clear out the edge segments for the ray cast
  188.     (Assume full viewing angle)
  189.     
  190. **********************************/
  191.  
  192. void ClearClipSegs(void)
  193. {
  194.     solidsegs[0].top = -1;        /* Maximum angle */
  195.     solidsegs[0].bottom = ANGLE180 + clipshortangle;    /* First edge */
  196.     solidsegs[1].top = ANGLE180 - clipshortangle;        /* Left edge */
  197.     solidsegs[1].bottom = 0;        /* Minimum angle */
  198.     newend = solidsegs+2;
  199. }
  200.  
  201. /**********************************
  202.  
  203.     Clip and draw a given wall segment
  204.         
  205. **********************************/
  206.  
  207. void P_DrawSeg (saveseg_t *seg)
  208. {
  209.     Word    segplane;
  210.     Word    door;
  211.     door_t    *door_p;
  212.     unsigned short    span, tspan;
  213.     unsigned short    angle1, angle2;
  214.     int        texslide;
  215.     int        distance;
  216.     
  217.     if (seg->dir & DIR_DISABLEDFLAG) {    /* Segment shut down? */
  218.         return;        /* pushwall part*/
  219.     }
  220.  
  221.     segplane = (Word)seg->plane << 7;
  222.     rw_mintex = (Word)seg->min << 7;
  223.     rw_maxtex = (Word)seg->max << 7;
  224.     
  225. /* adjust pushwall segs */
  226.  
  227.     if (seg == pwallseg) {        /* Is this the active pushwall? */
  228.         if (seg->dir&1)    {    /* east/west*/
  229.             segplane += PushWallRec.pwallychange;
  230.         } else {    /* north/south*/
  231.             segplane += PushWallRec.pwallxchange;
  232.         }
  233.     }
  234.     
  235. /* get texture*/
  236.  
  237.     if (seg->texture >= 129) {    /* segment is a door */
  238.         door = seg->texture - 129;    /* Which door is this? */
  239.         door_p = &doors[door];
  240.         rw_texture = &textures[129 + (door_p->info>>1)][0];
  241.         texslide = door_p->position;
  242.         rw_mintex += texslide;
  243.     } else {
  244.         texslide = 0;
  245.         rw_texture = &textures[seg->texture][0];
  246.     }
  247.     
  248.     switch (seg->dir&3) {    /* mask off the flags*/
  249.     case di_north:
  250.         distance = viewx - segplane;
  251.         if (distance <= 0) {
  252.             return;        /* back side*/
  253.         }
  254.         rw_downside = FALSE;
  255.         rw_midpoint = viewy;
  256.         normalangle = 2*FINEANGLES/4;
  257.         angle1 = PointToAngle(segplane,rw_maxtex);
  258.         angle2 = PointToAngle(segplane,rw_mintex);
  259.         break;
  260.     case di_south:
  261.         distance = segplane - viewx;
  262.         if (distance <= 0) {
  263.             return;        /* back side*/
  264.         }
  265.         rw_downside = TRUE;
  266.         rw_midpoint = viewy;
  267.         normalangle = 0*FINEANGLES/4;
  268.         angle1 = PointToAngle(segplane,rw_mintex);
  269.         angle2 = PointToAngle(segplane,rw_maxtex);
  270.         break;
  271.     case di_east:
  272.         distance = viewy - segplane;
  273.         if (distance <= 0) {
  274.             return;        /* back side*/
  275.         }
  276.         rw_downside = TRUE;
  277.         rw_midpoint = viewx;
  278.         normalangle = 1*FINEANGLES/4;
  279.         angle1 = PointToAngle(rw_mintex,segplane);
  280.         angle2 = PointToAngle(rw_maxtex,segplane);
  281.         break;
  282.     case di_west:
  283.         distance = segplane - viewy;
  284.         if (distance <= 0) {
  285.             return;        /* back side*/
  286.         }
  287.         rw_downside = FALSE;
  288.         rw_midpoint = viewx;
  289.         normalangle = 3*FINEANGLES/4;
  290.         angle1 = PointToAngle(rw_maxtex,segplane);
  291.         angle2 = PointToAngle(rw_mintex,segplane);
  292.         break;
  293.     }
  294.  
  295. /* clip to view edges*/
  296.  
  297.     span = angle1 - angle2;
  298.     if (span >= 0x8000) {        /* Test for negative (32 bit clean) */
  299.         return;
  300.     }
  301.     angle1 -= centershort;
  302.     angle2 -= centershort;
  303.     ++angle2;    /* make angle 2 non inclusive*/
  304.     
  305.     tspan = angle1 + clipshortangle;
  306.     if (tspan > clipshortangle2) {
  307.         tspan -= clipshortangle2;
  308.         if (tspan >= span) {
  309.             return;    /* totally off the left edge*/
  310.         }
  311.         angle1 = clipshortangle;
  312.     }
  313.     tspan = clipshortangle - angle2;
  314.     if (tspan > clipshortangle2) {
  315.         tspan -= clipshortangle2;
  316.         if (tspan >= span) {
  317.             return;    /* totally off the left edge*/
  318.         }
  319.         angle2 = -clipshortangle;
  320.     }
  321.  
  322. /* calc center angle for texture mapping*/
  323.  
  324.     rw_centerangle = (centerangle-normalangle)&FINEMASK;
  325.     if (rw_centerangle > FINEANGLES/2) {
  326.         rw_centerangle -= FINEANGLES;
  327.     }
  328.     rw_centerangle += FINEANGLES/4;
  329.     
  330.     rw_midpoint -= texslide;
  331.     rw_mintex -= texslide;
  332.     
  333.     angle1 += ANGLE180;        /* adjust so angles are unsigned*/
  334.     angle2 += ANGLE180;
  335.     ClipWallSegment(angle1, angle2,seg,distance);
  336. }
  337.  
  338. /**********************************
  339.  
  340.     Returns True if some part of the BSP dividing line might be visible
  341.         
  342. **********************************/
  343.  
  344. Boolean CheckBSPNode(Word boxpos)
  345. {
  346.     short     angle1, angle2;
  347.     unsigned short    span, tspan;
  348.     unsigned short    uangle1, uangle2;
  349.     screenpost_t    *start;
  350.     Word *PosPtr;
  351.     int x1,y1,x2,y2;
  352.     
  353.     PosPtr = &checkcoord[boxpos][0];
  354.     x1 = bspcoord[PosPtr[0]];
  355.     y1 = bspcoord[PosPtr[1]];
  356.     x2 = bspcoord[PosPtr[2]];
  357.     y2 = bspcoord[PosPtr[3]];
  358.     
  359.     angle1 = PointToAngle(x1,y1) - centershort;
  360.     angle2 = PointToAngle(x2,y2) - centershort;
  361.     
  362. /* check clip list for an open space */
  363.  
  364.     span = angle1 - angle2;
  365.     if (span >= 0x8000) {
  366.         return TRUE;    /* sitting on a line*/
  367.     }
  368.     tspan = angle1 + clipshortangle;
  369.     if (tspan > clipshortangle2) {
  370.         tspan -= clipshortangle2;
  371.         if (tspan >= span) {
  372.             return FALSE;    /* totally off the left edge*/
  373.         }
  374.         angle1 = clipshortangle;
  375.     }
  376.     tspan = clipshortangle - angle2;
  377.     if (tspan > clipshortangle2) {
  378.         tspan -= clipshortangle2;
  379.         if (tspan >= span) {
  380.             return FALSE;    /* totally off the left edge*/
  381.         }
  382.         angle2 = -clipshortangle;
  383.     }
  384.  
  385.  
  386. /* find the first clippost that touches the source post (adjacent pixels are touching)*/
  387.     uangle1 = angle1 + ANGLE180;
  388.     uangle2 = angle2 + ANGLE180;
  389.     start = solidsegs;
  390.     while (start->bottom > uangle1+1) {
  391.         ++start;
  392.     }
  393.     if (uangle1 <= start->top && uangle2 >= start->bottom) {
  394.         return FALSE;    /* the clippost contains the new span*/
  395.     }
  396.     return TRUE;
  397. }
  398.  
  399.  
  400. /**********************************
  401.  
  402.     Draw one or more wall segments
  403.         
  404. **********************************/
  405.  
  406. void TerminalNode (saveseg_t *seg)
  407. {
  408.     for (;;) {                /* Forever? */
  409.         P_DrawSeg(seg);        /* Draw the wall segment (If visible) */
  410.         if (seg->dir & DIR_LASTSEGFLAG) {    /* Last segment in list? */
  411.             return;            /* Exit now */
  412.         }
  413.         ++seg;                /* Index to the next wall segment */
  414.     }
  415. }
  416.  
  417. /**********************************
  418.  
  419.     Render the 3D view by recursivly following the BSP tree
  420.     
  421. **********************************/
  422.  
  423. void RenderBSPNode(Word bspnum)
  424. {
  425.     savenode_t *bsp;    /* Pointer to the current BSP node */
  426.     Word side;            /* decision line */
  427.     Word coordinate;    /* Current coord */
  428.     Word savednum;        /* Save index */
  429.     Word savedcoordinate;    /* Save value */
  430.     Word boxpos;        /* Index to the coord table */
  431.  
  432.     bsp = &nodes[bspnum];        /* Get pointer to the current tree node */
  433.     if (bsp->dir & DIR_SEGFLAG) {        /* There is a segment here... */    
  434.         TerminalNode((saveseg_t *)bsp);    /* Render it */
  435.         return;                            /* Exit */
  436.     }
  437.     
  438. /* decision node */
  439.  
  440.     coordinate = bsp->plane<<7;        /* stored as half tiles*/
  441.     
  442.     if (bsp->dir) {                    /* True for vertical tiles */
  443.         side = viewx > coordinate;    /* vertical decision line*/
  444.         savednum = BSPLEFT + (side^1);    /* Left or right */
  445.     } else {
  446.         side = viewy > coordinate;    /* horizontal decision line*/
  447.         savednum = BSPTOP + (side^1);    /* Top or bottom */
  448.     }
  449.     
  450.     savedcoordinate = bspcoord[savednum];    /* Save this coord */
  451.     bspcoord[savednum] = coordinate;        /* Set my new coord boundary */
  452.     RenderBSPNode(bsp->children[side^1]);    /* recursively divide front space*/
  453.  
  454.     bspcoord[savednum] = savedcoordinate;    /* Restore the coord */
  455.     savednum ^= 1;                            /* Negate the index */
  456.     savedcoordinate = bspcoord[savednum];    /* Save the other side */
  457.     bspcoord[savednum] = coordinate;        /* Set the new side */
  458.     
  459. /* if the back side node is a single seg, don't bother explicitly checking visibility */
  460.  
  461.     if ( ! ( nodes[bsp->children[side]].dir & DIR_LASTSEGFLAG ) ) {
  462.     
  463.     /* don't flow into the back space if it is not going to be visible */
  464.  
  465.         if (viewx <= bspcoord[BSPLEFT]) {
  466.             boxpos = 0;
  467.         } else if (viewx < bspcoord[BSPRIGHT]) {
  468.             boxpos = 1;
  469.         } else {
  470.             boxpos = 2;
  471.         }
  472.         if (viewy > bspcoord[BSPTOP]) {
  473.             if (viewy < bspcoord[BSPBOTTOM]) {
  474.                 boxpos += 4;
  475.             } else {
  476.                 boxpos += 8;
  477.             }
  478.         }
  479.         if (!CheckBSPNode(boxpos)) {    /* Intersect possible? */
  480.             goto skipback;                /* Exit now then */
  481.         }
  482.     }
  483.     RenderBSPNode(bsp->children[side]);    /* recursively divide back space */
  484. skipback:
  485.     bspcoord[savednum] = savedcoordinate;
  486. }
  487.